package com.mccken.annotation.logoperator;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.util.CollectionUtils;

import com.mccken.annotation.common.MethodExecuteResult;
import com.mccken.annotation.logoperator.context.LogRecordContext;

import lombok.extern.slf4j.Slf4j;

/**
 * @program: mccken-collect
 * @description:
 * @author: mccken
 * @create: 2022-01-04 16:24
 **/
@Slf4j
public class LogRecordAdvisor implements MethodInterceptor {

	private LogRecordOperationSource logRecordOperationSource;

	@Override
	public Object invoke(MethodInvocation invocation) throws Throwable {
		Method method = invocation.getMethod();
		return execute(invocation, invocation.getThis(), method, invocation.getArguments());
	}
	
	private Object execute(MethodInvocation invoker, Object target, Method method, Object[] args) throws Throwable {
		Class<?> targetClass = getTargetClass(target);
		Object ret = null;
		MethodExecuteResult methodExecuteResult = new MethodExecuteResult(true, null, "");
		LogRecordContext.putEmptySpan(); // todo
		Collection<LogRecordOps> operations = new ArrayList<>();
		Map<String, String> functionNameAndReturnMap = new HashMap<>();
		
		try {
			operations = logRecordOperationSource.computeLogRecordOperations(method, targetClass);
			List<String> spElTemplates = getBeforeExecuteFunctionTemplate(operations);
			// 业务逻辑执行前的自定义函数解析
			functionNameAndReturnMap = processBeforeExecuteFunctionTemplate(spElTemplates, targetClass, method, args);
		} catch (Exception e) {
			log.error("log record parse before function exception", e);
		}
		
		try {
			ret = invoker.proceed();
		} catch (Exception e) {
			methodExecuteResult = new MethodExecuteResult(false, e, e.getMessage());
		}
		
		try {
			if (!CollectionUtils.isEmpty(operations)) {
				recordExecute(ret, method, args, operations, targetClass, methodExecuteResult.isSuccess(), methodExecuteResult.getThrowable(), functionNameAndReturnMap); 
			}
		} catch (Exception t) {
			// 记录日志错误，但是也不要影响业务
			log.error("log record parse exception", t);
		} finally {
			LogRecordContext.clear();
		}
		
		if (methodExecuteResult.getThrowable() != null) {
			throw methodExecuteResult.getThrowable();
		}
		
		return ret;
	}

	private void recordExecute(Object ret, Method method, Object[] args, Collection<LogRecordOps> operations, Class<?> targetClass, boolean success, Throwable throwable, Map<String, String> functionNameAndReturnMap) {
		
	}

	private Map<String, String> processBeforeExecuteFunctionTemplate(List<String> spElTemplates, Class<?> targetClass, Method method, Object[] args) {
		return null; //todo
	}

	private List<String> getBeforeExecuteFunctionTemplate(Collection<LogRecordOps> operations) {
		return null; // todo
	}

	private Class<?> getTargetClass(Object target) {
		return (Class<?>) target;
	}

	public static class LogRecordOps {
	}
}
